/*
 * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#define GPIO_OUTPUT_IO_A1     1 
#define GPIO_OUTPUT_IO_B2     2 
#define GPIO_OUTPUT_IO_B1     3 
#define GPIO_OUTPUT_IO_A2     4 
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_A1) | (1ULL<<GPIO_OUTPUT_IO_B2) | (1ULL<<GPIO_OUTPUT_IO_B1) | (1ULL<<GPIO_OUTPUT_IO_A2))

#define TIME_DLY1 8
#define TIME_DLY2 4

static void step_clockwise(void)
{
        //step 1 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 2 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 3 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 4 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 5 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 6 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 7 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 8 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
}

static void step_unclockwise(void)
{
        //step 8 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 7 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 6 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 5 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 4 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 1);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 3 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 0);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
        //step 2 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY1 / portTICK_PERIOD_MS);
        //step 1 
        gpio_set_level(GPIO_OUTPUT_IO_A1, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B2, 1);
        gpio_set_level(GPIO_OUTPUT_IO_B1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_A2, 0);
        vTaskDelay(TIME_DLY2 / portTICK_PERIOD_MS);
}

static void step_motor_task(void* arg)
{
    uint8_t count = 0, i;
    for(;;) {
        if(count % 2) {
            for(i = 0;i < 100; i++)
                step_unclockwise();
        } else {
            for(i = 0;i < 100; i++)
                step_clockwise();
        }
        count++;
    }
}

void app_main(void)
{
    printf("Step motor simulation\n");
    printf("You can use this code to test the step motor direction decode is working fine or not.\n");

    //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //interrupt of falling edge
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //set as input mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //enable pull-down mode
    io_conf.pull_down_en = 0;
    gpio_config(&io_conf);

    xTaskCreate(step_motor_task, "step_motor_task", 1024, NULL, 10, NULL);

    printf("Minimum free heap size: %"PRIu32" bytes\n", esp_get_minimum_free_heap_size());
}
